﻿using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Text;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using MVVM_CAD.Common;
using MVVM_CAD.Model;

namespace MVVM_CAD.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class SceneManagerViewModel : ViewModelBase
    {
        private SaveFileDialog saveFile;
        private OpenFileDialog openFile;

        #region HardCoded
        /// <summary>
        /// The <see cref="HardCoded" /> property's name.
        /// </summary>
        public const string HardCodedPropertyName = "HardCoded";

        private string _hardCode = string.Empty;

        /// <summary>
        /// Gets the HardCoded property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string HardCoded
        {
            get
            {
                return _hardCode;
            }

            set
            {
                if (_hardCode == value)
                {
                    return;
                }

                _hardCode = value;

                RaisePropertyChanged(HardCodedPropertyName);
            }
        } 
        #endregion

        #region HardCoded
        /// <summary>
        /// The <see cref="HardCoded" /> property's name.
        /// </summary>
        public const string HardCoded2PropertyName = "HardCoded2";

        private string _hardCode2 = string.Empty;

        /// <summary>
        /// Gets the HardCoded property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string HardCoded2
        {
            get
            {
                return _hardCode2;
            }

            set
            {
                if (_hardCode2 == value)
                {
                    return;
                }

                _hardCode2 = value;

                RaisePropertyChanged(HardCoded2PropertyName);
            }
        }
        #endregion
        private ObservableCollection<IFigure> DrawedFigures;

        /// <summary>
        /// The <see cref="FilesLoaded" /> property's name.
        /// </summary>
        public const string FilesLoadedPropertyName = "FilesLoaded";

        private ObservableCollection<string> _fileLoaded = new ObservableCollection<string>();

        /// <summary>
        /// Gets the FilesLoaded property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<string> FilesLoaded
        {
            get
            {
                return _fileLoaded;
            }

            set
            {
                if (_fileLoaded == value)
                {
                    return;
                }

                _fileLoaded = value;

                RaisePropertyChanged(FilesLoadedPropertyName);
            }
        }

        #region SaveStatus
        /// <summary>
        /// The <see cref="Status" /> property's name.
        /// </summary>
        public const string SaveStatusPropertyName = "Status";

        private string _savestatus = string.Empty;

        /// <summary>
        /// Gets the SaveStatus property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string Status
        {
            get
            {
                return _savestatus;
            }

            set
            {
                if (_savestatus == value)
                {
                    return;
                }

                var oldValue = _savestatus;
                _savestatus = value;

                RaisePropertyChanged(SaveStatusPropertyName);

            }
        }

        #endregion

        #region FileName
        /// <summary>
        /// The <see cref="FileName" /> property's name.
        /// </summary>
        public string FileNamePropertyName = "FileName";

        private string _fileName = string.Empty;

        /// <summary>
        /// Gets the FileName property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string FileName
        {
            get
            {
                return _fileName;
            }

            set
            {
                _fileName = value;

                RaisePropertyChanged(FileNamePropertyName);
            }
        }

        #endregion

        #region SaveFileToolCommand
        private ICommand _saveFileToolCommand = null;

        public ICommand SaveFileToolCommand
        {
            get
            {
                return _saveFileToolCommand ??
                       (_saveFileToolCommand = new RelayCommand(DisplaySaveFileDialog));
            }
        }

        #endregion

        #region SaveToFileToolCommand
        private ICommand _saveToFileToolCommand = null;

        public ICommand SaveToFileToolCommand
        {
            get
            {
                return _saveToFileToolCommand ??
                       (_saveToFileToolCommand = new RelayCommand(SaveFile));
            }
        }

        #endregion

        #region OpenToFileToolCommand
        private ICommand _openToFileToolCommand = null;

        public ICommand OpenToFileToolCommand
        {
            get
            {
                return _openToFileToolCommand ??
                       (_openToFileToolCommand = new RelayCommand<string>(OpenFile));
            }
        }

        #endregion
        
        private ICommand _openFileToolCommand = null;

        public ICommand OpenFileToolCommand
        {
            get
            {
                return _openFileToolCommand ??
                       (_openFileToolCommand = new RelayCommand(DisplayOpenFileDialog));
            }
        }

        private void DisplayOpenFileDialog()
        {
            try
            {
                var files = Directory.GetFiles(@"C:\CAD");
                foreach (var file in files)
                {
                    FilesLoaded.Add(file);
                }
                openFile = new OpenFileDialog { FileList = FilesLoaded };
                HardCoded2 += ".";
                Status = "Se han cargado los archivos encontrados.";
            }
            catch (Exception)
            {
                Status = "Se ha producido un error al tratar de obtener los archivos guardados.";
                throw;
            }
        }

        private void SaveFile()
        {
            try
            {
                var builder = new StringBuilder();
                foreach (var figure in DrawedFigures)
                {
                    builder.Append(figure.GetType());
                    builder.Append("$");
                    builder.Append(figure.Name);
                    builder.Append("$");
                    builder.Append(figure.DrawStatus);
                    builder.Append("$");
                    foreach (var point in figure.PointsCollection)
                    {
                        builder.Append(point.IsVertex);
                        builder.Append("$");
                        builder.Append(point.X);
                        builder.Append("$");
                        builder.Append(point.Y);
                        builder.Append("$");
                    }
                    builder.Append("|");
                }
                File.WriteAllText(string.Format(@"C:\CAD\{0}.cad", FileName), builder.ToString());
                Status = string.Format("El archivo {0}.cad se guardo exitosamente.", FileName);
            }
            catch (System.Exception)
            {
                Status = "Se ha producido un error al guardar el archivo.";
            }
        }

        private void OpenFile(string fileLoader)
        {
            string file = File.ReadAllText(fileLoader);
            var figures = file.Split('|');
            int il = 0;
            foreach (var figure in figures)
            {
                if (il == figures.Length-1)
                {
                    break;
                }
                var figureTokens = figure.Split('$');
                var figureLoad = FigureFactory.GetFigure(figureTokens[0]);
                figureLoad.Name = figureTokens[1];
                figureLoad.DrawStatus = figureTokens[2] == "Completed" ? DrawStatus.Completed: DrawStatus.Incompleted;
                for (int i = 3; i < figureTokens.Length-1; i = i + 3)
                {
                    var point = new CustomPoint(Convert.ToDouble(figureTokens[i+1]),Convert.ToDouble(figureTokens[i+2]), Colors.Black)
                                    {IsVertex = Convert.ToBoolean(figureTokens[i])};
                    figureLoad.PointsCollection.Add(point);
                }
                DrawedFigures.Add(figureLoad);
                il++;
                Messenger.Default.Send(DrawedFigures);
            }
        }

        private void DisplaySaveFileDialog()
        {
            saveFile = new SaveFileDialog { CollectionToSave = DrawedFigures };
            HardCoded+=".";
        }
        
        /// <summary>
        /// Initializes a new instance of the SceneManager class.
        /// </summary>
        public SceneManagerViewModel(ObservableCollection<IFigure> drawedFigures, Canvas canvas)
        {
            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
            }
            else
            {
                DrawedFigures = drawedFigures;
            }
        }

        protected Canvas Canvas{ get; set; }
    }

}